/**
 * \file
 *
 * Allocate blocks from disk
 */
#include "kfs.hpp"            // block_index_t
#include "kfs_impl.hpp"

/**
 * Same semantics as std::auto_ptr.
 */
class AllocBlockRef
{
public:
    /**
     * Allocate a new block.
     *
    explicit AllocBlockRef(kfs::Impl*);
    */

    /**
     * Take ownership of an existing block.
     */
    AllocBlockRef(kfs::Impl*, block_index_t block);

    /**
     * Free the block that we own, if any.
     */
    ~AllocBlockRef();

    /**
     * Destructive copy semantics.
     */
    AllocBlockRef& operator=(AllocBlockRef&);

    block_index_t get() const;

    block_index_t release();

private:

    /**
     * Default constructor is not available.
     */
    AllocBlockRef();

    friend void swap(AllocBlockRef&, AllocBlockRef&);

    block_index_t block;

    kfs::Impl* impl;
};

/**
 * Same semantics as std::auto_ptr.
 */
class ContiguousAllocBlockRef
{
public:

    class Iterator;

    /**
     * Allocate a contiguous range of blocks or throw an exception.
     */
    ContiguousAllocBlockRef(kfs::Impl*, block_index_t numBlocks);

    /**
     * Take ownership of an existing range of blocks.  The size of the range
     * is end - begin.
     */
    ContiguousAllocBlockRef(kfs::Impl*, block_index_t begin,
        block_index_t end);

    /**
     * Free the block that we own, if any.
     */
    ~ContiguousAllocBlockRef();

    /**
     * Destructive copy semantics.
     */
    ContiguousAllocBlockRef& operator=(ContiguousAllocBlockRef&);

    Iterator begin();

    Iterator end();

    void release();

private:

    /**
     * Default constructor is not available.
     */
    ContiguousAllocBlockRef();

    friend void swap(ContiguousAllocBlockRef&, ContiguousAllocBlockRef&);

    block_index_t m_begin, m_end;

    kfs::Impl* impl;
};

/**
 */
class ContiguousAllocBlockRef::Iterator
{
public:

    Iterator()
    : container(0), value(blockid_nil)
    {}

    block_index_t operator*()
    {
        validateDeref();
        return value;
    }

    /** Advance the iterator. Prefix increment.
     */
    block_index_t& operator++()
    {
        validateAdvance();
        return ++value;
    }

    /** Advance the iterator. Postfix increment.
     */
    block_index_t operator++(int)
    {
        validateAdvance();
        return value++;
    }

private:

    friend class ContiguousAllocBlockRef;

    void validateDeref();

    void validateAdvance();

    Iterator(ContiguousAllocBlockRef* container, block_index_t value)
    : container(container), value(value)
    {}

    ContiguousAllocBlockRef* container;

    block_index_t value;
};
